package com.zt.chatglm.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author: zt
 * @Description: 签名工具包；过期时间30分钟，缓存时间29分钟
 * @create: 2024-05-20 21:53
 */
@Slf4j
public class BearerTokenUtils {

    /**
     * 过期时间：默认30分钟
     */
    private static final long EXPIRE_TIME = 30 * 60 * 1000L;

    /**
     * 使用google的guava包中的Cache来实现缓存
     */
    private static Cache<String, String> cache = CacheBuilder.newBuilder()
            .expireAfterWrite(EXPIRE_TIME - (60 * 1000L), TimeUnit.MILLISECONDS)
            .build();


    public static String getToken(String apiKey, String apiSecret) {
        // 1. 判断是否存在缓存
        String token = cache.getIfPresent(apiKey);
        if (token != null) {
            return token;
        }
        // 2. 创建token
        token = createToken(apiKey, apiSecret);
        // 3. 放入缓存中
        cache.put(apiKey, token);
        return token;
    }


    /**
     * 使用jwt创建token
     * https://open.bigmodel.cn/dev/api#http_auth、
     * header:
     *      {"alg":"HS256","sign_type":"SIGN"}
     *      alg : 属性表示签名使用的算法，默认为 HMAC SHA256（写为HS256）
     *      sign_type : 属性表示令牌的类型，JWT 令牌统一写为 SIGN 。
     * payload:
     *      {"api_key":{ApiKey.id},"exp":1682503829130, "timestamp":1682503820130}
     *      api_key : 属性表示用户标识 id，即用户API Key的{id}部分
     *      exp : 属性表示生成的JWT的过期时间，客户端控制，单位为毫秒
     *      timestamp : 属性表示当前时间戳，单位为毫秒
     */
    private static String createToken(String apiKey, String apiSecret) {
        // 1. 采用HMAC算法对密钥加密
        Algorithm algorithm = Algorithm.HMAC256(apiSecret.getBytes(StandardCharsets.UTF_8));

        // 2. 构建payload
        Map<String, Object> payload = new HashMap<>();
        payload.put("api_key", apiKey);
        payload.put("exp", System.currentTimeMillis() + EXPIRE_TIME);
        payload.put("timestamp", Calendar.getInstance().getTimeInMillis());

        // 3. 构建header
        Map<String, Object> header = new HashMap<>();
        header.put("alg", "HS256");
        header.put("sign_type", "SIGN");

        // 4. 构建token
        String newToken = JWT.create()
                .withPayload(payload)
                .withHeader(header)
                .sign(algorithm);

        return newToken;
    }
}
